home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / concur.com / CONCUR.DOC < prev    next >
Encoding:
Text File  |  1988-10-11  |  17.4 KB  |  421 lines

  1.  
  2.  
  3.  
  4.                 CONCURRENT PROGRAMMING IN TURBO C
  5.              ======================================
  6.  
  7.  
  8.     Documentation with "CONCUR.C"           Richard Dickerson
  9.     Version 1.00                            4129 Friendly Way
  10.     Date : Oct 15th, 1988                   Memphis, TN 38115
  11.                                             CIS ID: 73346,1217
  12.  
  13.  
  14.                           Introduction
  15.                           ------------
  16.  
  17. A  couple  of years ago, I came across a  concurrent  programming 
  18. module called CONCUR.PAS written by Hans Passant.  At the time, a 
  19. similar  set  of  routines didn't exist  for  the  C  programming 
  20. language,  so  I  set out to use  Mr.  Passant's  inspiration  to 
  21. develop  CONCUR.C.   About  the time I  was  finishing  CONCUR.C, 
  22. Thomas  Wagner  developed CTASK.C - a routine that  enables  true 
  23. multi-tasking.   Although this program module is  less  ambitious 
  24. than  CTASK.C, it is smaller and easier to use, and has  built-in 
  25. window  management routines that CTASK.C lacks.  I have used  Mr. 
  26. Passant's ideas, but the mechanism for saving and restoring  task 
  27. stacks and windows is slightly different owing to the differences 
  28. between Pascal and C.
  29.  
  30. Multi-tasking  is a process where several independent  pieces  of  
  31. code  (tasks)  compete  for execution.  Obviously,  the  CPU  can 
  32. execute only one task at a time.  The trick is to allow each task 
  33. to execute for a small amount of time,  after which the next task 
  34. is executed.  If this happens often enough,  the computer appears 
  35. to  run all of the tasks at the same time  :  true  multi-tasking 
  36. behavior.
  37.  
  38. The   process  of  suspending  the  currently  active  task   and 
  39. activating  the next is called a "context-switch".  All variables
  40. that are used by the task to be suspended (the task-context) must
  41. be  saved  so the task can be reactivated and continue  where  it
  42. left off when the task is again eligible for execution. Generally
  43. the  task-context  is made up of the current processor  registers
  44. and the stack.  Saving all the registers and preserving the  task
  45. stack  is therefore enough.
  46.  
  47. Turbo C is perfectly suited for this type of context-switch.   It 
  48. saves all of its function parameters and local variables  on  the 
  49. stack.   The  context of each task can therefor be  preserved  by 
  50. allocating  a  stack for each individual task.  The  task-context 
  51. switch function then only has to save the processor registers  on 
  52. the  task-stack,  set the stackpointer to the task stack for  the 
  53. next  task  to execute and restore the registers for  that  task.  
  54. There  is  however a catch, some variables used in  the  Turbo  C 
  55. library   belong  to  the task-context  (Example  :  the   _video 
  56. variable).   Also,  the  programmer  may  introduce  some  global 
  57. variables  that are used by more than one task.  The kernel takes 
  58. care  for the shared library variables.  It saves them in  global 
  59. structures  stack   upon  a context-switch.   The  programmer  is 
  60. responsible   for  protecting  the  shared  use  of  any   global 
  61. variables.  An example is given in the kernel-code. 
  62.  
  63. Left  to discuss is the mechanism that forces a  context  switch.  
  64. True  multi-tasking  operating  systems  always  use  a  hardware 
  65. interrupt,  triggered by a timer. The mechanism used in  CONCUR.C 
  66. is  a  simple coded call to the  context-switch  function.   This  
  67. method is known as "concurrent programming" and is popularized by 
  68. MODULA-2  .  The disadvantage of the latter mechanism   is   that  
  69. a   context  switch  does  not  occur  until  explicitly   called 
  70. for.   A  badly coded task may contain a long  or  infinite  loop 
  71. without  a  call  to  the  context  switch  function.  The   task  
  72. continues   to  execute  without any   concurrent   tasks   being  
  73. executed. 
  74.  
  75. The   big  advantage  of concurrent programming  however  is  the  
  76. simplification   of  the kernel.  A  hardware  triggered  context  
  77. switch  may suspend a task that is executing a  library  routine. 
  78. The Turbo C library is non-reentrant (for the same reasons DOS is 
  79. non-reentrant).   The   kernel would therefor have  to  save  all  
  80. library  data  structures  on  a context  switch,  a  very  time-
  81. consuming operation. 
  82.  
  83.          
  84.  
  85.                               Tasks
  86.                               -----
  87.  
  88. Tasks in CONCUR are simple,  parameterless Turbo functions.  Each 
  89. task   has   a   tasknumber and a private  area  in   the   Turbo  
  90. stack  segment for its stack : the task stack. A  program  always 
  91. contains one task :  the main program. By convention it has  task 
  92. number  0. Other  tasks are eligible for execution by  installing  
  93. them.  The install function claims an area of memory for the task 
  94. stack  and creates  a stack frame for the task.  Once a  task  is 
  95. installed it can never end execution and must never call  another 
  96. one directly.  
  97.  
  98. The  task install function needs the start address for the task , 
  99. the stack size needed, and  the task number.  The amount of stack 
  100. needed for  a task depends on the size of its local variables and 
  101. the  recursion depth  (if  any).  Failing to assign enough  stack 
  102. to  a   task  may cause erratic program behavior at  worst  or  a 
  103. "stack  overflow"   or "heap/stack" collision run time  error  at 
  104. best.  
  105.  
  106.                          The task stacks
  107.                          ---------------
  108.  
  109. Each  task participating in the concurrent programming scheme  is 
  110. assigned  a reserved area in the Turbo stack segment for its  own 
  111. stack.  This area should be reserved at start-up of the  program.  
  112. A  call  to the function <installtask> takes a   chunk  from  the 
  113. stack  and  assigns  it to the task being   installed.   A  stack  
  114. pointer is created,  pointing into the stack,  and is saved  into 
  115. the  global structure jpr[taskind], where taskind is the  current 
  116. task  index.   The task stack  is initialized with  the  register 
  117. contents  for the task.  The task is now ready to run,  activated 
  118. by a call to <switchta>.
  119.  
  120.  
  121.  
  122.                          Task switching
  123.                          --------------
  124.  
  125. The  concurrent  programming method hinges around  the   function 
  126. <switchta>.   This  function  is responsible  for   the   context 
  127. switch  needed  to deactivate the current task and  activate  the 
  128. next. <switchta> takes the following steps :
  129.  
  130.         1. Saves all data registers on the stack.
  131.         2. Checks the stack pointer for any stack overflow.
  132.         3. Saves  the  stack  pointer  (SS:SP)  in  the   global 
  133.            structure jpr[<taskind>].
  134.         4. Scans <maxtasks> for the next installed task.
  135.         5. Retrieves the stack pointer for that task.
  136.         6. Assigns <taskind> the task number of the new task.
  137.         7. Restores all data registers from the new task's stack.
  138.         8. Continues execution in the new task.
  139.  
  140. Task  switching does not occur until <switchta> is called.   This 
  141. restriction  makes the distinction between concurrent programming 
  142. and   multi-tasking.   A  multi-tasking  system  initiates   task  
  143. switching   independent from whatever task is  running,   usually  
  144. triggered   by  a clock interrupt.  This means  that  when   your  
  145. program  should  behave like a true  multi-tasking  program,  the 
  146. tasks should call <switchta> frequently and should avoid  lengthy 
  147. execution.
  148.  
  149.  
  150.                           Sharing input
  151.                           -------------
  152.  
  153. The  above  mentioned  restrictions  imposed  by  the  concurrent 
  154. programming model are most severe when reading from the keyboard.  
  155. Whenever a keyboard function <cgets, getch, getche ...) is coded, 
  156. Turbo  C transfers control  to  a library function  that  accepts 
  157. keyboard  input  and only returns when "Enter" is pressed.  While 
  158. this  is happening, no calls to <switchta> are made : the  entire 
  159. program "hangs" until input is ready. 
  160.  
  161. CONCUR.C   contains  a replacement <getche> function that  avoids 
  162. the  input  problems.  It is left to the  programmer  to  provide 
  163. similar string input functions.
  164.  
  165. The  keyboard must be shared when two or more tasks  need  input.  
  166. The   functions  <claiminput> and <releaseinput> take   care   of 
  167. that.   A  task  needing  input  calls  <claiminput>.   The  flag 
  168. <inputbusy>  is set.  The task now gets control over <input>.  As 
  169. soon as input is completed,  <releaseinput> is called,  releasing 
  170. the keyboard for other tasks.
  171.  
  172. Another  task needing input should call <claiminput> too.  If  it 
  173. finds  <inputbusy>  set, <switchta>  is called until  the   first  
  174. task claiming <input> releases the keyboard,  allowing the second 
  175. task to take control over the keyboard.
  176.  
  177.  
  178.                          Sharing output
  179.                          --------------
  180.  
  181. The above mentioned sharing problems also exist for output to the 
  182. screen.  Switchta.obj therefore automatically manages the  screen 
  183. output  for all tasks that use functions outputting  directly  to 
  184. the  console(cprintf, cputs, ...).  Each concurrent task has  its 
  185. own window on the screen.  Initially,  each task gets a window of 
  186. full  screen  size.  Upon activation,  the task should  call  the 
  187. function  <taskwindow>  to shrink  its  window to a part  of  the 
  188. screen   reserved   for   that task.   The   function   <border> 
  189. optionally draws a border  around that window. 
  190.  
  191.  
  192.  
  193.                         Function entries
  194.                         ----------------
  195.  
  196.        The following functions in CONCUR.C may be called :
  197.  
  198.  
  199. - void installtask (int Task number,  paragraphs, *function). This      
  200.      function should be called to install a task.  <Function>  is      
  201.      the   function  name  of the task and  must be of  the  type      
  202.      void  <task  name(void)>".  <Paragraphs>  is the  amount  of 
  203.      stack    needed    by    the     task    (in    paragraphs).       
  204.      <Task_number> is the task number for the installed task  and 
  205.      should range from 1 to 15.
  206.  
  207. -  void switchta(void).  This  function  does the context  switch 
  208.      from  the currently active task to the next installed  task.  
  209.      Switchta() also preserves and restores the task windows  and 
  210.      text attributes.
  211.  
  212.  -  void  taskwindow (int x1,y1,x2,y2,attribute).  This  function 
  213.      should be called by  each  task (including task 0,  the main 
  214.      program   !!)   to reserve a portion of the screen  for  its 
  215.      output.  <x1, y1> are the screen coordinates for  the  upper 
  216.      left  corner,   <x2,   y2> is the lower  right  corner,  and 
  217.      <attribute>  is the attribute for window text. Each call  to 
  218.      <switchta>  will preserve and restore these      values  for 
  219.      the  task  window.   In this manner,  one  window  may  have 
  220.      blinking   text   while   the  others   may   have   normal,      
  221.      inverse, high, or low video attributes.
  222.  
  223. -  void border (char *name).  Draws a border around the window of 
  224.     the  current  task. <name> is shown centered on  top  of  the 
  225.     window.
  226.  
  227.  
  228.  
  229.                          Program design
  230.                          --------------
  231.  
  232. The following basic steps should be made when designing a program 
  233. using the concurrent programming method :
  234.  
  235. 1. Make  a  logical  division in your program into  actions  that  
  236. should   occur   concurrently.  This will  produce   the   tasks.  
  237. Remember   that   the main program always acts as  one   of   the 
  238. tasks,  you  may want to use it to monitor the execution  of  the 
  239. entire  program.  Avoid having too many tasks,  the   more  tasks  
  240. are present,  the slower each of them will run.  
  241.  
  242.  
  243. 2. Choose  a screen layout for the windows of each task producing 
  244. screen output.  If you have a color monitor, be liberal with  the 
  245. use  of  TextColor  and  TextBackground.  Have  the  tasks   call 
  246. <taskwindow>/<border>  as  soon  as they  start  execution.
  247.  
  248. 3. Write the code for each concurrent task. Decide where calls to 
  249. <switchta> should be made.  Each concurrent task should at  least  
  250. contain an infinite loop,  so a call should  be  made inside that 
  251. loop. Inspect other loops and place calls at the deepest  nesting 
  252. levels. 
  253.  
  254. 4. Include the header-files :
  255.      1. #include <concur.h>
  256.      2. #include <stdio.h>
  257.      3  #include <conio.h>
  258.  
  259.  
  260. 5. Inspect your code for tasks that need input from the keyboard.  
  261. If  at least two tasks need input,  surround the input  code with 
  262. calls to <claiminput> and <releaseinput>.
  263.  
  264. 6. Inspect your code for shared access to global variables, files 
  265. and   devices.   Access  may need to be  controlled  through   an 
  266. access flag. Example :
  267.  
  268.              void   claimvar(void)          /* function */ 
  269.              {                                   
  270.                while (var_in_use) switchta(); /*claimvar*/
  271.                var_in_use  = 1;              
  272.              }                             /*releasevar*/
  273.  
  274.              void releasevar(void);      /*function task2*/
  275.              {                             
  276.                var_in_use = 0;         /*claimvar*/
  277.              }                             
  278.                                        /*releasevar*/
  279.  
  280.  
  281.         A prototype task would be coded as follows :
  282.          
  283.     void task1(void)
  284.         {
  285.           textbackground (..);/*Background color for task window*/
  286.           taskwindow (.....);      /*Create task window*/
  287.           textcolor (..);         /*Color for border*/
  288.           border (....);          /*Create border around window*/
  289.           textcolor (..);         /*Color for text in window*/
  290.           do
  291.           {
  292.             ....
  293.             switchta();      /*At least one call to switchta*/
  294.           }
  295.           while (1!=0);      /*Task should contain infinite loop*/
  296.         };
  297.  
  298.  
  299.  
  300. 7.Compile  using the small model libraries, and link in the  file 
  301. <SWITCHTA.OBJ>.  
  302.                           Restrictions
  303.                           ------------
  304.  
  305. 1. Access to global variables by more than one task is dangerous.  
  306. A   sharing  protocol is needed,  similar  to   the   <inputbusy> 
  307. method employed by the input driver.
  308.  
  309. 2. A maximum of 15 tasks may be installed.
  310.  
  311. 3.  Screen  I/O  must  use  cprintf(),cputs(),cscanf()  and   the 
  312. replacement getche() function to work within the task windows.  
  313.  
  314. 4. The installed tasks MUST be parameterless !!!
  315.  
  316.  
  317.  
  318.                    Problems and error messages
  319.                    ---------------------------
  320.  
  321.         The  following  error messages may appear,  they will  abort  the 
  322.         program :
  323.  
  324.         -  "Task Error: Unexpected  End of Task ...".   Installed  
  325.           tasks  are  not  allowed  to  abort.  Revise your  code 
  326.           and make sure  a  task contains an infinite loop.
  327.      
  328.         - "Install Error: Illegal task number ...". Task  numbers 
  329.             should be in (1..15).
  330.  
  331. Failing  to  request enough stack space for a task may result  in 
  332. erratic behavior of the program. The stack of another task may be 
  333. destroyed without Turbo or CONCUR detecting the error.  Make sure 
  334. enough stack space is reserved for each task. As a rule of thumb, 
  335. add  the size of all local variables and divide by 16 to get  the 
  336. number  of paragraphs.  Add 20 for safety.  If the task does  any 
  337. recursion,  add  plenty more (depending on the maximum  recursion 
  338. depth).
  339.  
  340.                        Files in CONCUR.ARC
  341.                        -------------------
  342.  
  343.      1.   CONCUR.C     - The prototype program.
  344.      2.   CONCUR.H     - The header file for CONCUR.C
  345.      3.   SWITCHTA.OBJ - Task switching object file.  Link  this 
  346.           with your program.
  347.      4.   SWITCHTA.ASM - The source for switchta.obj
  348.      5.   CONCUR.DOC   - This file.
  349.  
  350.  
  351.  
  352. I am looking forward to your experience with  CONCUR.C.  Please
  353. let me now if you find any serious errors,  particularly the ones 
  354. that  will  hang up your computer.  My user ID on the  COMPUSERVE 
  355. network is [73346,1217].      
  356.  
  357.  
  358.                     Richard Dickerson
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.          ----------------end-of-author's-documentation---------------
  388.  
  389.                         Software Library Information:
  390.  
  391.                    This disk copy provided as a service of
  392.  
  393.                         The Public (Software) Library
  394.  
  395.          We are not the authors of this program, nor are we associated
  396.          with the author in any way other than as a distributor of the
  397.          program in accordance with the author's terms of distribution.
  398.  
  399.          Please direct shareware payments and specific questions about
  400.          this program to the author of the program, whose name appears
  401.          elsewhere in  this documentation. If you have trouble getting
  402.          in touch with the author,  we will do whatever we can to help
  403.          you with your questions. All programs have been tested and do
  404.          run.  To report problems,  please use the form that is in the
  405.          file PROBLEM.DOC on many of our disks or in other written for-
  406.          mat with screen printouts, if possible.  The P(s)L cannot de-
  407.          bug programs over the telephone.
  408.  
  409.          Disks in the P(s)L are updated monthly, so if you did not get
  410.          this disk  directly from the P(s)L,  you should be aware that
  411.          the files in this set may no  longer be the current versions.
  412.  
  413.          For a copy of the latest monthly software library newsletter
  414.          and a list of the 1,400+ disks in the library, call or write
  415.  
  416.                         The Public (Software) Library
  417.                               P.O.Box 35705 - F
  418.                            Houston, TX 77235-5705
  419.                                (713) 665-7017
  420.  
  421.